package com.feelingjos.security.core.validate.code;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import com.feelingjos.security.core.properties.SecurityProperties;

public class SmsCodeFilter extends OncePerRequestFilter implements InitializingBean{
	
	private AuthenticationFailureHandler authenticationFailureHandler;
	
	private SessionStrategy sessionStrategy=new HttpSessionSessionStrategy();

	private Set<String> urls=new HashSet<>();
	
	private SecurityProperties securityProperties;
	
	private AntPathMatcher pathMatcher=new AntPathMatcher();
	
	@Override
	public void afterPropertiesSet() throws ServletException {
		super.afterPropertiesSet();
		String[] configUrls=StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getCode().getSms().getUrl(), ",");
	    for (String configUrl : configUrls) {
			urls.add(configUrl);
		}
	    
	    urls.add("/authentication/mobile");
	}
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		
		boolean action=false;
		
		for (String url : urls) {
			if(pathMatcher.match(url, request.getRequestURI())) {
				action=true;
			}
		}
		if(action) {
			try {
				validate(new ServletWebRequest(request));
			} catch (ValidateCodeException e) {
				authenticationFailureHandler.onAuthenticationFailure(request, response, e);
				return;
			}
		}
		
		filterChain.doFilter(request, response);
		
	}

	private void validate(ServletWebRequest request) throws ServletRequestBindingException {
		ValidateCode codeinSession=(ValidateCode)sessionStrategy.getAttribute(request, ValidateCodeController.SESSION_KEY);
	
		String codeInRequest=ServletRequestUtils.getStringParameter(request.getRequest(),"smsCode");
		
		if(StringUtils.isBlank(codeInRequest)) {
			throw new ValidateCodeException("验证码的值不能为空");
		}
		
		if(codeinSession == null) {
			throw new ValidateCodeException("验证码不存在");
		}
		
		if(codeinSession.isExpried()) {
			sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
		    throw new ValidateCodeException("验证码已过期");
		}
		
		if(!StringUtils.equals(codeinSession.getCode(),codeInRequest)){
			throw new ValidateCodeException("验证码不匹配");
		}
		
		sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);
		
	}
	
	public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
		this.authenticationFailureHandler = authenticationFailureHandler;
	}
	
	public AuthenticationFailureHandler getAuthenticationFailureHandler() {
		return authenticationFailureHandler;
	}
	
	public void setUrls(Set<String> urls) {
		this.urls = urls;
	}
	
	public Set<String> getUrls() {
		return urls;
	}
	
	public void setSecurityProperties(SecurityProperties securityProperties) {
		this.securityProperties = securityProperties;
	}
	
	public SecurityProperties getSecurityProperties() {
		return securityProperties;
	}

}
